package com.train.mgr.modules.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.train.common.enums.AudioRuleEnum;
import com.train.mgr.modules.biz.dto.response.CalScoreResultVO;
import com.train.mgr.modules.biz.entity.AudioMetricRule;
import com.train.mgr.modules.biz.mapper.AudioMetricRuleMapper;
import com.train.mgr.modules.biz.service.IAudioMetricRuleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 音频指标评分规则 服务实现类
 * @author cxg
 * @date 2025-10-18
 */
@Slf4j
@RequiredArgsConstructor
@Service("IAudioMetricRuleService")
public class AudioMetricRuleServiceImpl extends ServiceImpl<AudioMetricRuleMapper, AudioMetricRule> implements IAudioMetricRuleService {


    /**
     * 左闭右开（scoreMinIn ≤ 分数 < scoreMaxIn）
     * @param metric
     * @param score:原始值
     * @return
     */
    @Override
    public AudioMetricRule findOneByMetricAndScore(String metric, double score) {
        return lambdaQuery()
                .eq(AudioMetricRule::getMetric, metric)
                .le(AudioMetricRule::getScoreMinIn, score)   // 左闭：ScoreMinIn ≤ score
                .ge(AudioMetricRule::getScoreMaxIn, score)   // 右闭：score <= ScoreMinIn
                .last("LIMIT 1")
                .one();
    }


    /**
     * 此方法只用于计算：平均音量,音量标准差,净语速,口头禅,重复或修正,长停顿
     * 计算分数（新增 rawValue 区间匹配）
     * @param metric   指标编码
     * @param aiValue  原始测量值（用于算分）
     * @return CalScoreResultVO
     */
    @Override
    public CalScoreResultVO calcByRule(String metric, double aiValue) {
        log.info("用表规则计算分数 维度:{}, AI值:{}", metric, aiValue);

        double rawValue = truncate(aiValue,2); //原始指标值（用于区间定位） --转换保留2位小数，不四舍五入
        // 1. 取配置
        List<AudioMetricRule> rules = lambdaQuery()
                .eq(AudioMetricRule::getMetric, metric)
                .list();
        if (rules.isEmpty()) {
            throw new IllegalArgumentException("无此指标：" + metric);
        }

        AudioMetricRule base = rules.get(0);
        // 2. 根据原始分得出规则分（保留 2 位小数）
        double scoreRaw = 100 - Math.abs(base.getBaseVal() - aiValue) * base.getCoeff();

        //重复次数计算
        if(AudioRuleEnum.repeat_fix.getCode().equals(metric) || AudioRuleEnum.crutch_word.getCode().equals(metric)
                || AudioRuleEnum.long_pause.getCode().equals(metric) ){
            scoreRaw = 100 - (aiValue * base.getCoeff());
        }
        log.info("根据原始值计算分数是：{}",scoreRaw);
        double score = Math.max(scoreRaw, base.getScoreMin()); // 兜底不低于表下限
        BigDecimal bdScore = BigDecimal.valueOf(score)
                .setScale(3, RoundingMode.HALF_UP);

        // 3. 用 rawValue 定位唯一记录（保留 2 位小数比较）
        BigDecimal bdRaw = BigDecimal.valueOf(rawValue)
                .setScale(3, RoundingMode.HALF_UP);
        AudioMetricRule hitRule = rules.stream()
                .filter(r -> bdRaw.compareTo(BigDecimal.valueOf(r.getRawMin())) >= 0
                        && bdRaw.compareTo(BigDecimal.valueOf(r.getRawMax())) <= 0)
                .findFirst()
                .orElse(null);
        if (hitRule == null) {
            log.error("*****************原始值区间未命中 metric={}, rawValue={}", metric, rawValue);
            return new CalScoreResultVO(); // 或抛异常
        }
//
//        // 4. 二次校验：得分落在该记录的分数区间（闭合）—— BigDecimal 版本
//        BigDecimal scoreMin = BigDecimal.valueOf(hitRule.getScoreMinIn());
//        BigDecimal scoreMax = hitRule.getScoreMaxIn() == null
//                ? BigDecimal.valueOf(100)
//                : BigDecimal.valueOf(hitRule.getScoreMaxIn());
//
//        if (bdScore.compareTo(scoreMin) < 0
//                || bdScore.compareTo(scoreMax) > 0) {
//            log.error("**************分数区间未命中 metric={}, score={}, range=[{}, {}]",
//                    metric, bdScore, scoreMin, scoreMax);
//            return new CalScoreResultVO(); // 或抛异常
//        }

        // 5. 封装返回
        CalScoreResultVO vo = new CalScoreResultVO();
        vo.setScore(bdScore);
        vo.setLevelCode(hitRule.getLevelCode());
        vo.setLevelName(hitRule.getLevelName());
        vo.setDescription(hitRule.getDescription());
        return vo;
    }

    /**
     * 「只保留 2 位小数，不做四舍五入」= 直接截断（舍去后面所有位）
     * @param value
     * @param places
     * @return
     */
    public double truncate(double value, int places) {
        if (places < 0) throw new IllegalArgumentException();
        long factor = (long) Math.pow(10, places);
        return (long) (value * factor) / (double) factor;
    }


    /**
     * 计算分数
     * @param metric
     * @param aiValue
     * @return
     */
    public CalScoreResultVO calcByRule_bak(String metric, double aiValue) {
        log.info("用表规则计算分数 计算维度类型:{}, AI反馈值:{}",metric,aiValue);
        // 1. 取配置
        LambdaQueryWrapper<AudioMetricRule> queryRuleWrapper = new LambdaQueryWrapper<AudioMetricRule>();
        queryRuleWrapper.eq(AudioMetricRule::getMetric,metric);
        List<AudioMetricRule> rulesList = baseMapper.selectList(queryRuleWrapper);

        if (rulesList.isEmpty()) {
            throw new IllegalArgumentException("无此指标：" + metric);
        }

        AudioMetricRule base = rulesList.get(0);
        /* 1. 算原始分 */
        double raw = 100 - Math.abs(base.getBaseVal() - aiValue) * base.getCoeff();
        //“兜底保护”——确保算出来的得分不会低于表里面配置的最低分
        double score = Math.max(raw, base.getScoreMin());

        /* 2. 精度策略 */
        BigDecimal bdScore;
        if (metric.endsWith("_percent") || metric.startsWith("eye_") || metric.startsWith("facial_")
                || metric.startsWith("head_") || metric.startsWith("mental_")) {
            // 百分制保留 1 位小数
            bdScore = BigDecimal.valueOf(score).setScale(3, RoundingMode.HALF_UP);
        } else {
//            if(metric.endsWith("_speed")){
//                bdScore = BigDecimal.valueOf(aiValue);
//            }else{
                // 次/分、字/分 取整
                bdScore = BigDecimal.valueOf(Math.round(score));
            //}
        }

        /* 3. 区间匹配 */
        for (AudioMetricRule r : rulesList) {
            boolean hit = bdScore.intValue() >= r.getScoreMinIn()
                    && (r.getScoreMaxIn() == null || bdScore.intValue() <= r.getScoreMaxIn());
            if (hit) {
                CalScoreResultVO rs = new CalScoreResultVO();
                rs.setScore(bdScore);
                rs.setLevelCode(r.getLevelCode());
                rs.setLevelName(r.getLevelName());
                rs.setDescription(r.getDescription());
                return rs;
            }
        }
        log.error("********分数区间未命中*******.");
       // throw new RuntimeException("分数区间未命中");
        return new CalScoreResultVO();
    }
}
